package net.pws.common.persistence.mapbean.model;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import net.pws.common.util.ArrayUtils;
import net.pws.common.persistence.EntityManager;
import net.pws.common.persistence.hibernate3.utils.IdGeneratorFactory;
import net.pws.common.persistence.hibernate3.utils.JdbcUtils;
import net.pws.common.persistence.hibernate3.utils.SQLBuilder;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;


public class MapBean {
    private static final Log logger = LogFactory.getLog(MapBean.class);
    
    public static final String DEFAULT_ID_COLUMN_NAME = "ID";
    
    private String tableName;
    
    private String idColumnName = DEFAULT_ID_COLUMN_NAME;
    
    private String id;
    
    private Map properties;
    
    public String getTableName() {
        return tableName;
    }
    
    public void setTableName(String tableName) {
        this.tableName = tableName;
    }
    
    public String getIdColumnName() {
        return idColumnName;
    }
    
    public void setIdColumnName(String idColumnName) {
        this.idColumnName = idColumnName;
    }
    
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    public Map getProperties() {
        return properties;
    }
    
    public void setProperties(Map properties) {
        this.properties = properties;
    }
    
    public void copyFrom(MapBean mapBean) {
        this.setTableName(mapBean.getTableName());
        this.setId(mapBean.getId());
        this.setIdColumnName(mapBean.getIdColumnName());
        Map properties = new HashMap();
        properties.putAll(mapBean.getProperties());
        this.setProperties(properties);
    }
    
    // 1.build an insert statement and parameters (CAUSTION:the parameter
    // index must be matched)
    // 2.invoke jdbctemplete to execute
    // 3.if the effected row number is 1 return true else return false;
    public boolean insert(JdbcTemplate jdbcTemplate) {
        
        String insertStatement = SQLBuilder.buildInsertStatement(tableName,
                                                                 idColumnName,
                                                                 properties);
        if (logger.isDebugEnabled()) {
            logger.debug("insertStatement is: " + insertStatement);
        }
        final String generatorId = IdGeneratorFactory.getInstance().generate();
        int rowEffected = jdbcTemplate.update(insertStatement,
                                              new PreparedStatementSetter() {
                                                  
                                                  public void setValues(PreparedStatement ps) throws SQLException {
                                                      // id is handled as
                                                      // special
                                                      if (null != getId() && !"".equals(getId())) {
                                                          // �Ѿ��˹�ָ��id
                                                          ps.setString(1,
                                                                       getId());
                                                      }
                                                      else {
                                                          ps.setString(1,
                                                                       generatorId);
                                                      }
                                                      // the other
                                                      JdbcUtils.setPreparedStatementParameters(ps,
                                                                                               2,
                                                                                               getProperties());
                                                  }
                                                  
                                              });
        
        boolean result = (rowEffected == 1);
        if (result) {
            setId(generatorId);
        }
        return result;
    }
    
    public boolean update(JdbcTemplate jdbcTemplate) {
        String updateStatement = SQLBuilder.buildUpdateStatement(tableName,
                                                                 idColumnName,
                                                                 properties);
        if (logger.isDebugEnabled()) {
            logger.debug("updateStatement is: " + updateStatement);
        }
        int rowEffected = jdbcTemplate.update(updateStatement,
                                              new PreparedStatementSetter() {
                                                  
                                                  public void setValues(PreparedStatement ps) throws SQLException {
                                                      
                                                      // the other
                                                      JdbcUtils.setPreparedStatementParameters(ps,
                                                                                               1,
                                                                                               getProperties());
                                                      // id is handled as
                                                      // special
                                                      ps.setString(getProperties().size() + 1,
                                                                   getId());
                                                  }
                                                  
                                              });
        
        return (rowEffected == 1);
    }
    
    public boolean remove(JdbcTemplate jdbcTemplate) {
        String removeStatement = SQLBuilder.buildRemoveStatement(tableName,
                                                                 idColumnName);
        
        int rowEffected = jdbcTemplate.update(removeStatement,
                                              new PreparedStatementSetter() {
                                                  
                                                  public void setValues(PreparedStatement ps) throws SQLException {
                                                      ps.setString(1, getId());
                                                  }
                                                  
                                              });
        
        return (rowEffected == 1);
    }
    
    public boolean insert(EntityManager entityManager) {
        String insertStatement = SQLBuilder.buildInsertStatement(tableName,
                                                                 idColumnName,
                                                                 properties);
        if (logger.isDebugEnabled()) {
            logger.debug("insertStatement is: " + insertStatement);
        }
        
        final String generatorId = IdGeneratorFactory.getInstance().generate();
        String tableId;
        if (null != getId() && !"".equals(getId())) {
            // �Ѿ��˹�ָ��id
            tableId = getId();
        }
        else {
            tableId = generatorId;
        }
        
        Object[] leftParameters = new Object[] { tableId };
        Object[] rightParameters = getProperties().values().toArray();
        Object[] parameters = ArrayUtils.concat(leftParameters, rightParameters);
        
        int rowEffected = entityManager.nativeExecute(insertStatement,
                                                      parameters);
        
        boolean result = (rowEffected == 1);
        if (result) {
            setId(generatorId);
        }
        return result;
    }
    
    public boolean update(EntityManager entityManager) {
        String updateStatement = SQLBuilder.buildUpdateStatement(tableName,
                                                                 idColumnName,
                                                                 properties);
        if (logger.isDebugEnabled()) {
            logger.debug("updateStatement is: " + updateStatement);
        }
        
        Object[] leftParameters = getProperties().values().toArray();
        Object[] rightParameters = new Object[] { getId() };
        
        Object[] parameters = ArrayUtils.concat(leftParameters, rightParameters);
        
        int rowEffected = entityManager.nativeExecute(updateStatement,
                                                      parameters);
        
        return (rowEffected == 1);
    }
    
    public boolean remove(EntityManager entityManager) {
        String removeStatement = SQLBuilder.buildRemoveStatement(tableName,
                                                                 idColumnName);
        int rowEffected = entityManager.nativeExecute(removeStatement,
                                                      new Object[] { getId() });
        
        return (rowEffected == 1);
    }
    
}
